package com.serial.comm.modular.serialPort.controller;

import com.alibaba.fastjson.JSON;
import com.serial.comm.config.rabbitmq.SerialMsgSender;
import com.serial.comm.core.constants.SerialConst;
import com.serial.comm.core.exception.*;
import com.serial.comm.core.exception.enums.ResponseCodeEnum;
import com.serial.comm.core.reqres.response.ResponseData;
import com.serial.comm.core.rest.fodb.FODBRestClient;
import com.serial.comm.core.telegram.utils.ITA2Util;
import com.serial.comm.core.utils.SerialUtils;
import com.serial.comm.core.utils.StringUtils;
import com.serial.comm.modular.serialPort.enums.FODBEnums;
import com.serial.comm.modular.serialPort.enums.TelegramEnum;
import com.serial.comm.modular.serialPort.model.FodbMsg;
import com.serial.comm.modular.serialPort.model.Origin;
import com.serial.comm.modular.serialPort.model.SerialiOptions;
import com.serial.comm.modular.serialPort.model.TelegramMQ;
import com.serial.comm.modular.serialPort.service.IOriginService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;

/**
 * 串口读写业务 控制器
 */
@RestController
public class SerialController {

    public static Logger log = LoggerFactory.getLogger(SerialController.class);

    public static CharsetEncoder ita2Encoder = new ITA2Util().newEncoder();

    @Resource
    private FODBRestClient fodbRestClient;

     @Resource
    private SerialMsgSender serialMsgSender;

     @Resource
    private IOriginService originService;

    @RequestMapping("/openSerialPort")
    public ResponseData openSerialPort(SerialiOptions options) {
        log.info(SerialConst.SysMessage.READY_TO_CONNECT);
        String comName = options.getComName();
        Integer speed = options.getSpeed();
        Integer dataBits = options.getDataBits();
        Integer stopBits = options.getStopBits();

        log.info(">>>>>>串口连接参数：串口名称：{}， 波特率:{},数据位：{}，停止位：{}", comName, speed, dataBits, stopBits);
        try {
            SerialUtils.openPort(comName, speed, dataBits, stopBits);

        } catch (SerialPortParameterFailure serialPortParameterFailure) {
            throw new SerialPortParameterFailure(ResponseCodeEnum.SERIAL_PORT_PARAMETER_FAILURE);
        } catch (NotASerialPort notASerialPort) {
            throw new NotASerialPort(ResponseCodeEnum.NOT_A_SERIAL_PORT);
        } catch (NoSuchPort noSuchPort) {
            throw new NoSuchPort(ResponseCodeEnum.NO_SUCH_PORT);
        } catch (PortInUse portInUse) {
            throw new PortInUse(ResponseCodeEnum.PORT_IN_USE);
        } catch (TooManyListeners tooManyListeners) {
            throw new TooManyListeners(ResponseCodeEnum.TOO_MANY_LISTENERS);
        }
        return ResponseData.success(SerialConst.BusinessMessage.OPEN_SUCCESS);
    }

    @RequestMapping("/closeSerialPort")
    public ResponseData closeSerialPort() {
        SerialUtils.closePort();
        return ResponseData.success(SerialConst.BusinessMessage.CLOSE_SUCCESS);
    }

    @RequestMapping("/sendReadMsg")
    public String sendMessage(String msg) {
        serialMsgSender.sendReadBaseQueueMsg(msg);
        return "success";
    }

    @RequestMapping(value = "/sendQueueMsg", method = RequestMethod.POST)
    public ResponseData sendWriteMsg(@RequestBody FodbMsg fodbMsg) {
        //入参校验
        if (fodbMsg == null) {
            return ResponseData.error("待写入的报文参数为空");
        }
        if (StringUtils.isEmpty(fodbMsg.getMessage())) {
            return ResponseData.error("待写入的报文内容不能为空");
        }
        if (StringUtils.isEmpty(fodbMsg.getSid())) {
            return ResponseData.error("报文uuid不能为空");
        }
        String msg = fodbMsg.getMessage();
        String uuid = fodbMsg.getSid();
        String messageText = JSON.toJSONString(msg);
        log.info(">>>>>>收到串口写入请求,电报内容:{}", messageText);
        TelegramMQ telegramMQ = new TelegramMQ();
        telegramMQ.setGuid(uuid);
        telegramMQ.setTelegramText(msg);
        serialMsgSender.sendWriteQueueMsg(telegramMQ);
        return ResponseData.success(SerialConst.SysMessage.WRITE_MSG_SUCCESS);
    }

    /**
     * 通过HTTP接口发送串口消息
     *
     * @return
     */
    @RequestMapping(value = "/sendMsg", method = RequestMethod.POST)
    public ResponseData sendMsg(String message,String sid) {
        if(StringUtils.isBlank(message))return ResponseData.error("message 不能为空!");
        if(StringUtils.isBlank(sid))return ResponseData.error("sid 不能为空!");

        String uuid = sid;
        try {
            log.info(">>>>>>收到串口写入请求:{}", JSON.toJSONString(message));
            ByteBuffer sourceBytes = ita2Encoder.encode(CharBuffer.wrap(message.toCharArray()));
            SerialUtils.sendToPort(sourceBytes.array());
            //入库成功写入的电报
            Origin origin = new Origin(message, TelegramEnum.SUCCESS.getCode(), TelegramEnum.WRITE.getCode(), uuid);
            originService.createOriginTelegramAndGetId(origin);
            log.info(">>>>>>写入-电报已入库");

            //反馈FODB写入结果
            log.info(">>>>>>准备通知fodb写入结果");
            String result = fodbRestClient.fodbRequireApi(FODBEnums.WRITE_SUCCESS.getMessage(), FODBEnums.WRITE_SUCCESS.getCode(), origin.getGuid());
            log.info("已通知fodb写入结果，FODB写入接口返回值:{}", JSON.toJSONString(result));

            return ResponseData.success(SerialConst.SysMessage.WRITE_MSG_SUCCESS);
        } catch (Exception e) {
            log.error(">>>>>>串口消息写入异常");

            //反馈FODB写入结果
            log.info(">>>>>>准备通知fodb写入结果");
            String result = fodbRestClient.fodbRequireApi(e.getMessage(), FODBEnums.WRITE_FAILED.getCode(), uuid);
            log.info(">>>>>>已通知fodb写入结果，FODB写入接口返回值:{}", JSON.toJSONString(result));


            Origin origin = new Origin(message, TelegramEnum.FAILED.getCode(), TelegramEnum.WRITE.getCode(), uuid);
            originService.createOriginTelegramAndGetId(origin);
            log.info(">>>>>>写入-异常电报已入库");
            return ResponseData.error(e.getMessage());
        }
    }

}
